<?php
/**
 * Copyright (c) 2011 Jakob Sack <mail@jakobsack.de>
 * This file is licensed under the Affero General Public License version 3 or
 * later.
 * See the COPYING-README file.
 */
/**
 *
 * The following SQL statement is just a help for developers and will not be
 * executed!
 *
 * CREATE TABLE calendar_calendars (
 *     id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
 *     userid VARCHAR(255),
 *     displayname VARCHAR(100),
 *     uri VARCHAR(100),
 *     active INTEGER UNSIGNED NOT NULL DEFAULT '0',
 *     ctag INTEGER UNSIGNED NOT NULL DEFAULT '0',
 *     calendarorder INTEGER UNSIGNED NOT NULL DEFAULT '0',
 *     calendarcolor VARCHAR(10),
 *     timezone TEXT,
 *     components VARCHAR(20)
 * );
 *
 */

/**
 * This class manages our calendars
 */
class PCalendarModelCalendar extends JModelLegacy
{
   /**
    * @brief Returns the list of calendars for a specific user.
    * @param string $uid User ID
    * @param boolean $active Only return calendars with this $active state, default(=false) is don't care
    * @return array
    */
   public function allCalendars($uid, $active=false) {
      $db = PFactory::getDbo();
      $active_where = '';
      if (!is_null($active) && $active) {
         $active_where = 'AND `active` = '.intval($active);
      }
      $query = "SELECT * FROM *PREFIX*calendar_calendars WHERE userid = ".$db->quote($uid)." ".$active_where;
      $db->setQuery(PUtil::replaceOCPrefix($query));
      $calendars = $db->loadAssocList();

      foreach ($calendars as $k => $cal) {
         $calendars[$k]['permissions'] = OCP\PERMISSION_CREATE
            | OCP\PERMISSION_READ | OCP\PERMISSION_UPDATE
            | OCP\PERMISSION_DELETE | OCP\PERMISSION_SHARE;
      }
      $calendars = array_merge($calendars, OCP\Share::getItemsSharedWith('calendar', OC_Share_Backend_Calendar::FORMAT_CALENDAR));

      return $calendars;
   }

   /**
    * @brief Returns the list of calendars for a principal (DAV term of user)
    * @param string $principaluri
    * @return array
    */
   public function allCalendarsWherePrincipalURIIs($principaluri) {
      $uid = $this->extractUserID($principaluri);
      return $this->allCalendars($uid);
   }

   /**
    * @brief Gets the data of one calendar
    * @param integer $id
    * @return associative array
    */
   public function find($id) {
      $db = PFactory::getDbo();
      $query = "SELECT * FROM *PREFIX*calendar_calendars WHERE id = ".intval($id);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      $row = $db->loadAssoc();
      if(!$row)
         return false; 

      $master = PFactory::getMasterUser();
      if($row['userid'] != OC_USER::getUser() && $master->id != PCompanyHelper::getSubUserMaster($row['userid'])) {
         $sharedCalendar = OCP\Share::getItemSharedWithBySource('calendar', $id);
         if (!$sharedCalendar || !($sharedCalendar['permissions'] & OCP\PERMISSION_READ)) {
            return $row; // I have to return the row so e.g. PCalendarModelObject->getOwner() works.
         }
         $row['permissions'] = $sharedCalendar['permissions'];
      } else {
         $row['permissions'] = OCP\PERMISSION_ALL;
      }
      return $row;
   }

   /**
    * @brief Gets the calendar data by userid (only use for check interview has calendar or not)
    * @param string $userid
    * @return associative array
    */
   public function findByUid($userid) {
      $db = PFactory::getDbo();
      $query = "SELECT * FROM *PREFIX*calendar_calendars WHERE userid = ".$db->quote($userid);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      $row = $db->loadAssoc();
      if ( $row ) {
         $row['permissions'] = OCP\PERMISSION_ALL;
      }
      return $row;
   }

   /**
    * @brief Creates a new calendar
    * @param string $userid
    * @param string $name
    * @param string $components Default: "VEVENT,VTODO,VJOURNAL"
    * @param string $timezone Default: null
    * @param integer $order Default: 1
    * @param string $color Default: null, format: '#RRGGBB(AA)'
    * @return insertid
    */
   public function addCalendar($userid,$name,$components='VEVENT,VTODO,VJOURNAL',$timezone=null,$order=0,$color=null) {
      $all = $this->allCalendars($userid);
      $uris = array();
      foreach($all as $i) {
         $uris[] = $i['uri'];
      }

      $uri = $this->createURI($name, $uris );

      $db = PFactory::getDbo();
      $query = "INSERT INTO *PREFIX*calendar_calendars (`userid`,`displayname`,`uri`,`ctag`,`calendarorder`,`calendarcolor`,`timezone`,`components`) VALUES (".$db->quote($userid).",".$db->quote($name).",".$db->quote($uri).", 1 ,".$db->quote($order).",".$db->quote($color).",".$db->quote($timezone).",".$db->quote($components).")";
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      } else {
         $insertid = $db->insertid();
      }

      OCP\Util::emitHook('OC_Calendar', 'addCalendar', $insertid);

      return $insertid;
   }

   /**
    * @brief Creates default calendars
    * @param string $userid
    * @return boolean
    */
   public function addDefaultCalendars($userid = null) {
      if(is_null($userid)) {
         $userid = OC_USER::getUser();
      }

      $id = $this->addCalendar($userid,'Default calendar');

      return true;
   }

   /**
    * @brief Creates a new calendar from the data sabredav provides
    * @param string $principaluri
    * @param string $uri
    * @param string $name
    * @param string $components
    * @param string $timezone
    * @param integer $order
    * @param string $color format: '#RRGGBB(AA)'
    * @return insertid
    */
   public function addCalendarFromDAVData($principaluri,$uri,$name,$components,$timezone,$order,$color) {
      $userid = $this->extractUserID($principaluri);

      $db = PFactory::getDbo();
      $query = "INSERT INTO *PREFIX*calendar_calendars (`userid`,`displayname`,`uri`,`ctag`,`calendarorder`,`calendarcolor`,`timezone`,`components`) VALUES (".$db->quote($userid).",".$db->quote($name).",".$db->quote($uri).", 1 ,".$db->quote($order).",".$db->quote($color).",".$db->quote($timezone).",".$db->quote($components).")";
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      } else {
         $insertid = $db->insertid();
      }

      OCP\Util::emitHook('OC_Calendar', 'addCalendar', $insertid);

      return $insertid;
   }

   /**
    * @brief Edits a calendar
    * @param integer $id
    * @param string $name Default: null
    * @param string $components Default: null
    * @param string $timezone Default: null
    * @param integer $order Default: null
    * @param string $color Default: null, format: '#RRGGBB(AA)'
    * @return boolean
    *
    * Values not null will be set
    */
   public function editCalendar($id,$name=null,$components=null,$timezone=null,$order=null,$color=null) {
      // Need these ones for checking uri
      $calendar = $this->find($id);
      $master = PFactory::getMasterUser(); 
      if (!$calendar || ($calendar['userid'] != OC_USER::getUser() && $master->id != PCompanyHelper::getSubUserMaster($calendar['userid']))) {
         $sharedCalendar = OCP\Share::getItemSharedWithBySource('calendar', $id);
         if (!$sharedCalendar || !($sharedCalendar['permissions'] & OCP\PERMISSION_UPDATE)) {
            $this->setError("你没有权限编辑该日历!");
            return false;
         }
      }

      // Keep old stuff
      if(is_null($name)) $name = $calendar['displayname'];
      if(is_null($components)) $components = $calendar['components'];
      if(is_null($timezone)) $timezone = $calendar['timezone'];
      if(is_null($order)) $order = $calendar['calendarorder'];
      if(is_null($color)) $color = $calendar['calendarcolor'];

      $db = PFactory::getDbo();
      $query = "UPDATE *PREFIX*calendar_calendars SET `displayname`=".$db->quote($name).",`calendarorder`=".$db->quote($order).",`calendarcolor`=".$db->quote($color).",`timezone`=".$db->quote($timezone).",`components`=".$db->quote($components).",`ctag`=`ctag`+1 WHERE id = ".intval($id);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      }

      OCP\Util::emitHook('OC_Calendar', 'editCalendar', $id);
      return true;
   }

   /**
    * @brief Sets a calendar (in)active
    * @param integer $id
    * @param boolean $active
    * @return boolean
    */
   public function setCalendarActive($id,$active) {
      $calendar = $this->find($id);
      if (!$calendar || $calendar['userid'] != OC_USER::getUser()) {
         $sharedCalendar = OCP\Share::getItemSharedWithBySource('calendar', $id);
         if (!$sharedCalendar || !($sharedCalendar['permissions'] & OCP\PERMISSION_UPDATE)) {
            $this->setError("你没有权限编辑该日历!");
            return false;
         }
      }

      $db = PFactory::getDbo();
      $query = "UPDATE *PREFIX*calendar_calendars SET `active` = ".$db->quote($active)." WHERE id = ".intval($id);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      }

      return true;
   }

   /**
    * @brief Updates ctag for calendar
    * @param integer $id
    * @return boolean
    */
   public function touchCalendar($id) {
      $db = PFactory::getDbo();
      $query = "UPDATE *PREFIX*calendar_calendars SET `ctag` = `ctag` + 1 WHERE id = ".intval($id);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      }

      return true;
   }

   /**
    * @brief removes a calendar
    * @param integer $id
    * @return boolean
    */
   public function deleteCalendar($id) {
      $calendar = $this->find($id);
      $master = PFactory::getMasterUser(); 
      if (!$calendar || ($calendar['userid'] != OC_USER::getUser() && $master->id != PCompanyHelper::getSubUserMaster($calendar['userid']))) {
         $sharedCalendar = OCP\Share::getItemSharedWithBySource('calendar', $id);
         if (!$sharedCalendar || !($sharedCalendar['permissions'] & OCP\PERMISSION_DELETE)) {
            $this->setError("你没有权限删除该日历!");
            return false;
         }
      }

      $db = PFactory::getDbo();
      $query = "DELETE FROM *PREFIX*calendar_calendars WHERE id = ".intval($id);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      }

      $query = "DELETE FROM *PREFIX*calendar_objects WHERE calendarid = ".intval($id);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      }

      OCP\Share::unshareAll('calendar', $id);

      OCP\Util::emitHook('OC_Calendar', 'deleteCalendar', $id);
      if(OC_USER::isLoggedIn() and count($this->allCalendars(OC_USER::getUser())) == 0) {
         $this->addDefaultCalendars(OC_USER::getUser());
      }

      return true;
   }

   /**
    * @brief merges two calendars
    * @param integer $id1
    * @param integer $id2
    * @return boolean
    */
   public function mergeCalendar($id1, $id2) {
      $calendar = $this->find($id1);
      $master = PFactory::getMasterUser(); 
      if (!$calendar || ($calendar['userid'] != OC_USER::getUser() && $master->id != PCompanyHelper::getSubUserMaster($calendar['userid']))) {
         $sharedCalendar = OCP\Share::getItemSharedWithBySource('calendar', $id1);
         if (!$sharedCalendar || !($sharedCalendar['permissions'] & OCP\PERMISSION_UPDATE)) {
            $this->setError("你没有权限添加到该日历!");
            return false;
         }
      }

      $db = PFactory::getDbo();
      $query = "UPDATE *PREFIX*calendar_objects SET `calendarid` = ".intval($id1)." WHERE calendarid = ".intval($id2);
      $db->setQuery(PUtil::replaceOCPrefix($query));
      if (!$db->execute()) {
         $this->setError("网络异常，请重试！");
         return false;
      }

      $this->touchCalendar($id1);
      $this->deleteCalendar($id2);
   }

   /**
    * @brief Creates a URI for Calendar
    * @param string $name name of the calendar
    * @param array  $existing existing calendar URIs
    * @return string uri
    */
   public function createURI($name,$existing) {
      $strip=array(' ','/','?','&');//these may break sync clients
      $name=str_replace($strip,'',$name);
      $name = strtolower($name);

      $newname = $name;
      $i = 1;
      while(in_array($newname,$existing)) {
         $newname = $name.$i;
         $i = $i + 1;
      }
      return $newname;
   }

   /**
    * @brief gets the userid from a principal path
    * @return string
    */
   public function extractUserID($principaluri) {
      list($prefix,$userid) = Sabre_DAV_URLUtil::splitPath($principaluri);
      return $userid;
   }

   /**
    * @brief returns the possible color for calendars
    * @return array
    */
   public function getCalendarColorOptions() {
      return array(
         '#ff0000', // "Red"
         '#b3dc6c', // "Green"
         '#ffff00', // "Yellow"
         '#808000', // "Olive"
         '#ffa500', // "Orange"
         '#ff7f50', // "Coral"
         '#ee82ee', // "Violet"
         '#9fc6e7', // "light blue"
      );
   }

   /**
    * @brief generates the Event Source Info for our JS
    * @param array $calendar calendar data
    * @param int $jobid job id
    * @param share $share share key to access one event
    * @return array
    */
   public function getEventSourceInfo($calendar,$jobid=0, $share='') {
      $uri = $jobid ? '&jobid='.$jobid : '';
      $uri .= $share ? '&share='.$share : '';
      return array(
         'url' => OCP\Util::linkTo('calendar', 'ajax/events.php').'?calendar_id='.$calendar['id'].$uri,
         'backgroundColor' => '#f5f5f5',
         'borderColor' => '#b7b7b7',
         'textColor' => '#333333',
         'cache' => false,
      );
   }

   /*
    * @brief checks if a calendar name is available for a user
    * @param string $calendarname
    * @param string $userid
    * @return boolean
    */
   public function isCalendarNameavailable($calendarname, $userid) {
      $calendars = $this->allCalendars($userid);
      foreach($calendars as $calendar) {
         if($calendar['displayname'] == $calendarname) {
            return false;
         }
      }
      return true;
   }

   /*
    * @brief generates the text color for the calendar
    * @param string $calendarcolor rgb calendar color code in hex format (with or without the leading #)
    * (this function doesn't pay attention on the alpha value of rgba color codes)
    * @return boolean
    */
   public function generateTextColor($calendarcolor) {
      if(substr_count($calendarcolor, '#') == 1) {
         $calendarcolor = substr($calendarcolor,1);
      }
      $red = hexdec(substr($calendarcolor,0,2));
      $green = hexdec(substr($calendarcolor,2,2));
      $blue = hexdec(substr($calendarcolor,2,2));
      //recommendation by W3C
      $computation = ((($red * 299) + ($green * 587) + ($blue * 114)) / 1000);
      return ($computation > 130)?'#000000':'#FAFAFA';
   }
}
